﻿// -----------------------------------------------------------------------
// <copyright file="Face_Detection.cs" company="">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace FaceRecognition
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Drawing.Imaging;
    using System.Linq;
    using System.Text;
    using System.Timers;
    using Emgu.CV;
    using Emgu.CV.CvEnum;
    using Emgu.CV.Structure;


    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class Face_Detection : IFace_Detection
    {
        private Capture cap;
        private HaarCascade haar;
        public  Image<Bgr, byte> frame;
        public int no_faces;
        Bitmap [] bmpCrop_arr;
        public int arr_size;
        private bool camera_disposed=false;
        public Face_Detection()
        {
           // cap = new Capture(0);
            haar = new HaarCascade("..\\haarcascade_frontalface_alt2.xml");
            frame = null;
            no_faces = 0;
            bmpCrop_arr = new Bitmap[10];
        }
       public void Close_Cam()
       {
           if (cap != null)
           {
               cap.Dispose();

               camera_disposed = true;
           }
       }
      
        public Image<Bgr, byte> Capture_Frame()
        {
            //if camera is closed then create one
            //else it's olready opened
            try
            {
                if (cap == null)
                    cap = new Capture(0);
                if (camera_disposed == true)
                {
                    cap = new Capture(0);
                    camera_disposed = false;
                }
                    ///////////////////////////
                Image<Bgr, byte> nextFrame = cap.QueryFrame();

                return nextFrame;
            }
            catch (Exception e ){
                throw e;
            }
        }
        public void Open_Camera()
        {
            try
            {
                if (cap == null)
                    cap = new Capture(1);
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public Image Detect_Face(Image<Bgr, byte> nextFrame,ref Image<Bgr,byte> returned_frame)
        {
            no_faces = 0;
            arr_size = 0;
            if (nextFrame != null)
            {
    
                // there's only one channel (greyscale), hence the zero index
                //var faces = nextFrame.DetectHaarCascade(haar)[0];
                Image<Gray, byte> grayframe = nextFrame.Convert<Gray, byte>();
                var faces = grayframe.DetectHaarCascade(
                                haar, 1.4, 4,
                                HAAR_DETECTION_TYPE.DO_CANNY_PRUNING,
                                new Size(nextFrame.Width / 8, nextFrame.Height / 8)
                                )[0];

    
                foreach (var face in faces)
                {
                    no_faces++;
                    nextFrame.Draw(face.rect, new Bgr(0, double.MaxValue, 0), 3);
                    Bitmap bmpImage = new Bitmap(grayframe.ToBitmap());
                    Bitmap bmpCrop = bmpImage.Clone(face.rect, bmpImage.PixelFormat);
                    bmpCrop_arr[arr_size] = bmpCrop;
                    arr_size++;
                }
          
                returned_frame = nextFrame;
                //////////////////////////////
                if (no_faces == 0)
                    return null;
                ////if no of faces >1 call  a func to decide which face is bigger to return it
                int max = 0;
                
                if (arr_size > 1)
                {

                   int i=0;
                   for (int j = 1; j < arr_size; j++)
                   {
                       if (bmpCrop_arr[i].Size.Height > bmpCrop_arr[j].Size.Height && bmpCrop_arr[i].Size.Width > bmpCrop_arr[j].Size.Width)
                       {
                           max = i;
                       }
                       else
                       {
                           i = j;
                           max = j;

                       }


                   }

                }
                return bmpCrop_arr[max];
            }
            return null;
        }
        public int Count_Faces()
        {
            int temp = no_faces;
            no_faces = 0;
            return temp;
        }
        public Bitmap[] Faces_Pics()
        {
            return bmpCrop_arr;
        }

        public Image Get_User_Face(Size size)
        {
            try
            {
                Image<Bgr, byte> temp = null;
                frame = Capture_Frame();
                Image img = Detect_Face(frame, ref temp);

                if (img == null)
                    return null;
                //crop the face    

                /////////////////////////////////////////////
                //if (arr_size != 0)
                //    return ResizeImage( bmpCrop_arr[0],size);
                //call gray / resize functions from preprocess face class
                //= GrayImage(temp_frame);
                //  img = GrayImage(bmpCrop_arr[max]);
                img = ResizeImage(img, size);
                return img;
            }
            catch (Exception e)
            {
                throw e;
            }
        }
       internal  Image ResizeImage(Image imgToResize, Size size)
        {
            //if (imgToResize == null)
            //    return null;
            int sourceWidth = imgToResize.Width;
            int sourceHeight = imgToResize.Height;

            float nPercent = 0;
            float nPercentW = 0;
            float nPercentH = 0;

            nPercentW = ((float)size.Width / (float)sourceWidth);
            nPercentH = ((float)size.Height / (float)sourceHeight);

            if (nPercentH < nPercentW)
                nPercent = nPercentH;
            else
                nPercent = nPercentW;

            int destWidth = (int)(sourceWidth * nPercent);
            int destHeight = (int)(sourceHeight * nPercent);

            Bitmap b = new Bitmap(destWidth, destHeight);
            Graphics g = Graphics.FromImage((Image)b);
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;

            g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
            g.Dispose();

            return (Image)b;

        }
        private static Image GrayImage(Bitmap original)
        {
          //  return img.Convert<Gray, byte>().ToBitmap();
            Bitmap newBitmap = new Bitmap(original.Width, original.Height);

            //get a graphics object from the new image
            Graphics g = Graphics.FromImage(newBitmap);

            //create the grayscale ColorMatrix
            ColorMatrix colorMatrix = new ColorMatrix(
               new float[][] 
      {
         new float[] {.3f, .3f, .3f, 0, 0},
         new float[] {.59f, .59f, .59f, 0, 0},
         new float[] {.11f, .11f, .11f, 0, 0},
         new float[] {0, 0, 0, 1, 0},
         new float[] {0, 0, 0, 0, 1}
      });

            //create some image attributes
            ImageAttributes attributes = new ImageAttributes();

            //set the color matrix attribute
            attributes.SetColorMatrix(colorMatrix);

            //draw the original image on the new image
            //using the grayscale color matrix
            g.DrawImage(original, new Rectangle(0, 0, original.Width, original.Height),
               0, 0, original.Width, original.Height, GraphicsUnit.Pixel, attributes);

            //dispose the Graphics object
            g.Dispose();
            return (Image)newBitmap;
        }




        
    }
}
